/*
 * -------------------------------------------------------------------------
 * 升级管理器
 * -------------------------------------------------------------------------
 */

/*app对象实例*/
let app;
const _           = require('lodash');
const os          = require('os');
const path        = require('path');
const semver      = require('semver');
const electron    = require('electron');
const { exec }    = require('child_process');
const logger      = require('./logger');
const packageJson = require('../package.json');
const arch        = require('../helper/arch');
const file        = require('../helper/file/log');
const is          = require('../helper/is');
const appEvents   = require('./app/events');
const downloader  = require('../helper/downloader');
const IPC_UPDATER = require('./ipc/dict').IPC_UPDATER;
const ipcMain     = electron.ipcMain;

/**
 * 初始化
 * @param appInstance
 */
function initialize (appInstance) {
    /*复写app实例*/
    app = appInstance;
    
    /*渲染进程通知检测更新*/
    ipcMain.on(IPC_UPDATER.RENDER_REQUEST, checkUpdate);
    
    /*渲染进程确认更新*/
    ipcMain.on(IPC_UPDATER.RENDER_CONFIRM, (e, data) => downloadConfirm(data));
}

/**
 * 检查更新
 * @return {Promise<void>}
 */
async function checkUpdate () {
    /*读取feed文件*/
    notify(IPC_UPDATER.CHECK_INFO, '检测新版本...');
    
    /*订阅地址*/
    let url = packageJson.configs.feed.updater;
    
    /*获取订阅信息*/
    await downloader.getUrl(url)
        
        /*搜索更新信息并通知新版本*/
        .then(ret => searchUpdate(ret.data))
        
        /*错误提示*/
        .catch((ret => notify(IPC_UPDATER.CHECK_ERROR, ret.errMsg, ret.data)));
}

/**
 * 检索更新设置
 * @param data
 * @returns {boolean}
 */
function searchUpdate (data) {
    try {
        /*解析feed*/
        let feed = JSON.parse(data);
        
        /*检测软件名称*/
        if (feed.name !== packageJson.appName) return notify(IPC_UPDATER.PARSE_INFO, '暂无可用版本');
        
        /*查找升级信息*/
        let electron = packageJson.configs.electron;
        let update   = _.find(feed.list, v => {
            const matchArch     = arch.getArch().toLowerCase() === v.arch.toLowerCase();
            const matchPlatform = electron.platform.toLowerCase() === v.platform.toLowerCase();
            const matchDevelop  = Boolean(v.develop) === is.electronDev();
            const matchVersion  = semver.gt(v.version, packageJson.version);
            return matchArch && matchPlatform && matchDevelop && matchVersion;
        });
        
        /*无升级信息*/
        if (!update) return notify(IPC_UPDATER.PARSE_INFO, '暂无可用版本');
        
        /*新版本通知*/
        return notify(IPC_UPDATER.NEW_VERSION, update);
    }
    catch (e) {
        return notify(IPC_UPDATER.PARSE_ERROR, '检测更新版本比对失败', e);
    }
};

/**
 * 确认下载升级包
 * @param update
 * @returns {boolean}
 */
async function downloadConfirm (update) {
    let { url } = update;
    
    /*无地址*/
    if (!url) return notify(IPC_UPDATER.DOWNLOAD_ERROR, '更新包地址检测失败');
    
    /*安装包本地保存目录*/
    let saveDir = path.join(app.getPath('exe'), '..', 'updater');
    
    /*尝试创建目录*/
    file.mkdir(saveDir);
    
    /*保存文件路径*/
    const savePath = path.join(saveDir, path.basename(url));
    
    /*下载文件*/
    notify(IPC_UPDATER.DOWNLOAD_INFO, '开始下载安装包');
    
    /*onProgress回调参数用于更新进度*/
    await downloader.saveUrl(url, savePath, (total, downloaded) => notify(IPC_UPDATER.DOWNLOAD_PROGRESS, { total, downloaded }))
        
        /*下载失败*/
        .catch(ret => notify(IPC_UPDATER.DOWNLOAD_ERROR, '安装包下载失败', ret.data))
        
        /*下载完成*/
        .then(() => {
            notify(IPC_UPDATER.DOWNLOAD_INFO, '安装包下载完毕');
            
            /*启动安装包*/
            runSetup(savePath);
        });
};

/**
 * 启动安装包
 * @param file
 */
function runSetup (file) {
    /*窗口自动关闭时间*/
    let closeSecond = 2;
    
    /*启动升级安装包*/
    exec(file);
    
    /*检测升级安装包是否启动成功*/
    let runCheck = setInterval(() => {
        exec('tasklist /FO CSV', (err, out) => {
            if (err) return notify(IPC_UPDATER.RUN_SETUP_ERROR, '安装包启动失败', err);
            
            /*检测程序运行列表中的安装包进程*/
            out.split(os.EOL).map(line => {
                if (line.indexOf(`"${path.basename(file)}"`) === 0) {
                    clearInterval(runCheck);
                    notify(IPC_UPDATER.RUN_SETUP_SUCCESS, `安装包启动成功，窗口${closeSecond}秒后自动关闭`);
                    setTimeout(appEvents.exit, closeSecond * 1e3); /*延迟退出软件*/
                }
            });
        });
    }, 5e2);
};

/**
 * 发送通知到渲染进程
 * @param eventName
 * @param data
 * @param err
 * @returns {boolean}
 */
function notify (eventName, data, err) {
    app.$windowMain.webContents.send(eventName, data);
    err && logger.error(err);
    return false;
};

/**
 * 导出
 * @type {{initialize: initialize}}
 */
module.exports = {
    initialize
};
